﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GameLibrary.Map
{
    [Serializable]
    public class RoadNetwork
    {
        #region variables

        private Dictionary<KeyValuePair<Position, Position>, Path> roadNetwork;

        #endregion

        #region constructor

        public RoadNetwork()
        {
            this.roadNetwork = new Dictionary<KeyValuePair<Position, Position>, Path>();
        }

        #endregion

        #region get move cost map
        /// <summary>
        /// Return move costmap of the road network.
        /// </summary>
        /// <returns></returns>
        public Dictionary<Position,Dictionary<Position,double>> GetMoveCostMap()
        {
            // this is the adjacency list
            Dictionary<Position, Dictionary<Position, double>> adjList =
                new Dictionary<Position, Dictionary<Position, double>>();

            foreach (var pair in this.roadNetwork.Keys)
            {
                if (adjList.ContainsKey(pair.Key) == false)
                    adjList.Add(pair.Key, new Dictionary<Position, double>());
                
                if (adjList.ContainsKey(pair.Value) == false)
                    adjList.Add(pair.Value, new Dictionary<Position, double>());
                
                var cost = this.roadNetwork[pair].TotalMoveCost;
                adjList[pair.Key].Add(pair.Value, cost);// add both as road is bidirectional
                adjList[pair.Value].Add(pair.Key, cost);
            }

            return adjList;
        }

        #endregion

        #region get path
         
        /// <summary>
        /// Return path bewteen positons.
        /// Return null if this path does not exist.
        /// </summary>
        /// <param name="pos1"></param>
        /// <param name="pos2"></param>
        /// <returns></returns>
        public Path GetPath(Position pos1, Position pos2)
        {
            KeyValuePair<Position, Position> keyValuePair1 =
                new KeyValuePair<Position, Position>(pos1, pos2);
            KeyValuePair<Position, Position> keyValuePair2 =
                new KeyValuePair<Position, Position>(pos2, pos1);

            if (this.roadNetwork.ContainsKey(keyValuePair1) == true)
                return this.roadNetwork[keyValuePair1];

            if (this.roadNetwork.ContainsKey(keyValuePair2) == true)
                return this.roadNetwork[keyValuePair2];

            return null;
        }

        #endregion

        #region add

        public void AddPath(Position pos1, Position pos2, Path path)
        {
            if(this.ContainsPath(pos1,pos2) == false)
                this.roadNetwork.Add(new KeyValuePair<Position,Position>(pos1,pos2),path);
        }

        #endregion

        #region remove

        /// <summary>
        /// Remove all path related to pos
        /// </summary>
        /// <param name="pos"></param>
        public void RemovePosition(Position pos)
        {
            var list = from key in this.roadNetwork.Keys
                       where key.Key == pos || key.Value == pos
                       select key;

            foreach (var keyValuePair in list)
                this.roadNetwork.Remove(keyValuePair);            
        }

        #endregion

        #region contains

        public bool ContainsPath(Position pos1, Position pos2)
        {
            KeyValuePair<Position, Position> kv1 =
                  new KeyValuePair<Position, Position>(pos1, pos2);
            KeyValuePair<Position, Position> kv2 =
                new KeyValuePair<Position, Position>(pos2, pos1);
            if (this.roadNetwork.ContainsKey(kv1) == true
                 || this.roadNetwork.ContainsKey(kv2) == true)
                return true;
            else
                return false;
        }

        #endregion

        #region values

        public IEnumerable<Path> Values
        {
            get
            {
                return this.roadNetwork.Values;
            }
        }

        #endregion
    }
}
